// * Map 就像 对象一样，是一个带 键 的数据项集合，但是它们最大的区别是 Map 允许任何类型的键(key)。

// * 创建map —— new Map()
const map = new Map()

// * 根据键存储值 —— map.set(key, value)
let obj = { name: 'John' }
map.set('1', 'str1') // 字符串键
map.set(2, 'str2') // 数字键
map.set(true, 'bool') // 布尔键
map.set(obj, 'obj') // 对象键

// * 根据键获取值 —— map.get(key)
console.log(map.get('1')) // str1
console.log(map.get(2)) // str2
console.log(map.get(true)) // bool
console.log(map.get(obj)) // obj

// * 判断键是否存在 —— map.has(key)
console.log(map.has('1')) // true
console.log(map.has(1)) // false

// * 删除键 —— map.delete(key)
map.delete('1')
console.log(map.has('1')) // false
console.log(map.get('1')) // undefined
console.log(map.size) // 2

// * 清空map —— map.clear()
map.clear()

// * 获取map长度 —— map.size
console.log(map.size) // 0

// 注意：不要使用 map[key] 的方式来获取或设置值，这样会将 map 视为普通对象，而不是 Map 对象。
// 请使用 map.get(key) 和 map.set(key, value) 等来操作 map 对象。

// * 链式调用，map.set 每次都会返回 map 自身。
const map2 = new Map()
map2.set('a', 1).set('b', 2).set('c', 3)
console.log(map2.get('c')) // 3

// * Map 迭代，如果要在 map 里使用循环，可以使用一下 三个方法：
const map3 = new Map([
	['a', 1],
	['b', 2],
	['c', 3],
])

map3.set('d', 4)

// * map.keys() —— 返回一个包含所有键的可迭代对象。
console.log(map3.keys()) // [Map Iterator] { 'a', 'b', 'c', 'd' }
for (const key of map3.keys()) console.log(key) // a b c d

// * map.values() —— 返回一个包含所有值的可迭代对象。
console.log(map3.values()) // [Map Iterator] { 1, 2, 3, 4 }
for (const value of map3.values()) console.log(value) // 1 2 3 4

// * map.entries() —— 返回一个包含所有实体 [key, value] 的可迭代对象，for..of 在默认情况下使用的就是这个。
console.log(map3.entries()) // [Map Entries] { [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ], [ 'd', 4 ] }
// 这两个相同
for (const entry of map3.entries()) console.log(entry) // [ 'a', 1 ] [ 'b', 2 ] [ 'c', 3 ] [ 'd', 4 ]
for (const entry2 of map3) console.log(entry2) // [ 'a', 1 ] [ 'b', 2 ] [ 'c', 3 ] [ 'd', 4 ]

// * map 迭代顺序就是创建顺序。
// map 有内建的 forEach 方法，与 Array 类似。
map3.forEach((value, key, map) => console.log(key, value)) // a 1 b 2 c 3 d 4

// * Object.entries(obj) 可将普通对象转为 map 所需要的数据格式。
// Object.entries 返回键/值对数组：[ ["name","John"], ["age", 30] ]。这就是 Map 所需要的格式。
let obj2 = { a: 1, b: 2, c: 3 }
let map4 = new Map(Object.entries(obj2))
console.log(map4.get('a')) // 1

// * Object.fromEntries([[key, value]]) 可将 map 数据（和二维数组一样）格式转为普通对象。
let arr = [
	['name', 'John'],
	['age', 30],
]
let map5 = new Map(arr)
let obj3 = Object.fromEntries(map5)
console.log(obj3.name) // John

// **************************************************************************************************************
// **************************************************************************************************************
// **************************************************************************************************************

// 适用场景：使用 Set 来存储不能重复的值，比通过使用数组的 find 方法检查是否重复更加高效。

// * Set 是一个“值的集合”（没有键），它的每一个值只能出现一次。

// * 创建set —— new Set() 值是可迭代对象（通常是数组）
const set = new Set()

// * 向 set 添加值 —— set.add(value)
set.add(1).add(2).add(3).add(3)
console.log(set.size) // 3 (重复的值只会被添加一次)

// * 判断值是否存在 —— set.has(value)
console.log(set.has(1)) // true
console.log(set.has(4)) // false

// * 删除值 —— set.delete(value)
set.delete(2)
console.log(set.size) // 2

// * 清空set —— set.clear()
set.clear()

// set.size —— 获取 set 长度
console.log(set.size) // 0

// * Set 迭代 —— 与 Map 类似，有 set.keys()、set.values()、set.entries()、set.forEach()、for..of 等方法。
const set2 = new Set([1, 2, 3, 4, 4])
for (const key of set2.keys()) console.log(key) // 1 2 3 4
for (const value of set2.values()) console.log(value) // 1 2 3 4（与 set.keys() 作用相同，为了兼容 map）
for (const entry of set2.entries()) console.log(entry) // [1, 1] [2, 2] [3, 3] [4, 4]（返回一个包含所有的实体 [value, value] 的可迭代对象,也是为了兼容 map）
for (const entry2 of set2) console.log(entry2) // 1 2 3 4
set2.forEach((value, key, set) => console.log(key, value)) // 1 1 2 2 3 3 4 4

// * 注：在 Map 和 Set 中迭代总是按照值插入的顺序进行的，所以我们不能说这些集合是无序的，但是我们不能对元素进行重新排序，也不能直接按其编号来获取元素。
